package com.android.people;

import java.util.ArrayList;
import java.util.ListIterator;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Camera;
import android.graphics.Canvas;
import android.graphics.ComposeShader;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.Adapter;
import android.widget.AdapterView;
import android.widget.Scroller;

import com.android.people.SlideImageViewService.BitmapAdapter;

public class CoverFlowView extends AdapterView<Adapter> {

	private final static boolean DEBUG = false;
	private final static String TAG = "CoverFlowView";

	// private ArrayList<Bitmap> mBitmapList;
	private ArrayList<Bitmap> mTransBitmapList = new ArrayList<Bitmap>();
	// private int mFirstPosition = 0;
	private int mMaxCount = 7;
	private int mMidPoint;
	private int mAreaWidth = 120;
	private int mAreaHeight = 150;
	private int mAreaStepX = 30;
	private int mAreaStepY = 0;
	private float mRotateAngle = 60.0f;
	private float mReflection = 0.1f;
	private float mDepth = 100.0f;

	private static final int LEFT = 0;
	private static final int RIGHT = 1;
	private static final int MID = 2;
	private static final int LEFT_RIGHT_MOST = 3;
	private static final int RIGHT_LEFT_MOST = 4;

	private static final int END_FLING = 0;

	private static final int FILL = 0;
	private static final int SCALE = 1;

	private ArrayList<Area> mAreaList = new ArrayList<Area>();
	private Camera mCamera = new Camera();
	// private AreaAttribute[] mAreaAttribute = new AreaAttribute[2];
	private Adapter mAdapter;
	private Rect[] mLayoutRectInfo;
	private int mLeftSpanWithMid = 40;
	// private int mRightSpanWithMid = 40;
	// int mFirstPosition;

	private static final int TOUCH_MODE_DOWN = 10;
	private static final int TOUCH_MODE_FLING = 12;
	private static final int TOUCH_MODE_REST = 13;
	private static final int TOUCH_MODE_TAP = 14;
	private static final int TOUCH_MODE_DONE_WAITING = 15;

	private int mTouchMode = TOUCH_MODE_REST;
	private int mItemCount = 0;

	private Runnable mPendingCheckForLongPress;

	/**
	 * Determines speed during touch scrolling
	 */
	private VelocityTracker mVelocityTracker;

	/**
	 * Handles one frame of a fling
	 */
	private FlingRunnable mFlingRunnable;

	private MidAreaClickListener mMidAreaClickListener;
	private int mCurrentDirection = 0;

	private int mCurrentIdx = -1;
	public int mMoveCount = 0;
	public boolean isFling = false;
	private EndFlingListener mInterface;

	public interface EndFlingListener {
		public void HandleEndFlingEvent(boolean isLeft);

		public void HandleTouchMidCoverEvent();
	}
	
	public void SetFling(boolean fling) {
		isFling = fling;
	}

	public void setFlingInterface(EndFlingListener a) {
		mInterface = a;
	}

	public int CurrentIdx() {
		return mCurrentIdx;
	}

	public void SetCurrentIdx(int move) {
		mCurrentIdx = (mItemCount + move + mCurrentIdx) % mItemCount;
	}

	public int GetCount() {
		return mItemCount;
	}

	private class Area {
		Rect layout = new Rect();
		Rect clipRect = new Rect();
		Bitmap bmap;
		Matrix canvasMatrix;
		int type;
		// boolean deleted = false;
		float currentRotateAngle;
	}

	public CoverFlowView(Context context) {
		super(context);
		setWillNotDraw(false);
	}

	public CoverFlowView(Context context, AttributeSet attrs) {
		super(context, attrs);
		setWillNotDraw(false);
	}

	public CoverFlowView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		setWillNotDraw(false);
	}

	public CoverFlowView(Context context, int attributeId) {
		super(context);
		setWillNotDraw(false);
		initAttribute(attributeId);
	}

	public void initAttribute(int attributeId) {
		initAttribute(getContext(), attributeId);
		mMidPoint = mMaxCount / 2;
		mLayoutRectInfo = new Rect[mMaxCount];
		for (int i = 0; i < mMaxCount; i++) {
			mLayoutRectInfo[i] = new Rect();
		}
	}
	
	public void GCResource() {
	    for (Bitmap bm : mTransBitmapList) {
	        if (bm.isRecycled() == false) {
	            bm.recycle();
	        }
	    }
	    mTransBitmapList.clear();
	}

	public void setAdapter(Adapter adapter) {
		mAdapter = adapter;
		mTransBitmapList.clear();
		mAreaList.clear();
		scaleImageList(adapter);

		mItemCount = mTransBitmapList.size();
		mCurrentIdx = ((BitmapAdapter) adapter).GetInitIndex();

		requestLayout();
		invalidate();
	}

	public Adapter getAdapter() {
		return mAdapter;
	}

	public void setMidAreaClickListener(MidAreaClickListener mcl) {
		mMidAreaClickListener = mcl;
	}

	public interface MidAreaClickListener {
		void onClick();
	}

	public View getSelectedView() {
		return null;
	}

	// public int getSelection() {
	// return getFirstPosition() + mMidPoint;
	// }
	//
	// public void setSelection(int position) {
	// // mFirstPosition = position;
	// int leftCount = mMaxCount / 2;
	// int pos = position - leftCount;// getNextPosition(position, -
	// // leftCount);
	// // mFirstPosition = pos;
	// changeFirstPosition(pos);
	// requestLayout();
	// }

	private int getFirstPosition() {
		// return getFirstVisiblePosition();// mFirstPosition;
		return mCurrentIdx - mMaxCount / 2;
	}

	// TODO: OMS implementation
	private void changeFirstPosition(int pos) {
		// mFirstPosition = pos;

		// NOTE: OMS implementation
		// setFirstVisiblePosition(pos);
	}

	private class FlingRunnable implements Runnable {

		private Scroller mScroller;
		private int mLastFlingX;

		public boolean dragBack = false;
		public int prevIncreamentDeltaX = 0;
		public int moveSpan = 0;
		public int moveSpanMerge = 0;
		public int moveCount = 10;
		public boolean lastNeedMerge = false;
		public int index = 0;
		public boolean fromStart = false;

		public FlingRunnable() {
			mScroller = new Scroller(CoverFlowView.this.getContext());
		}

		public void startFling() {
			mTouchMode = TOUCH_MODE_FLING;
			post(this);
		}

		private void createMoveSpan(int span) {
			if (span < 0) {
				return;
			}
			if (prevIncreamentDeltaX < 0) {
				if (span > moveCount) {
					moveSpan = span / moveCount;
					if (span % moveCount > 0) {
						lastNeedMerge = true;
						moveSpanMerge = moveSpan + span % moveCount;
					}
				} else {
					moveSpan = 1;
					moveCount = span;
				}
			} else if (prevIncreamentDeltaX > 0) {
				if (span > moveCount) {
					moveSpan = -span / moveCount;
					if (span % moveCount > 0) {
						lastNeedMerge = true;
						moveSpanMerge = moveSpan - span % moveCount;
					}
				} else {
					moveSpan = -1;
					moveCount = span;
				}
			} else {
				LOGD("####ERROR: prevIncreamentDeltaX is zero####");
			}
		}

		public boolean startDragBack() {
			Area a = null;
			for (int i = 0; i < mAreaList.size(); i++) {
				a = mAreaList.get(i);
				if (a.bmap != null)
					break;
			}
			if (a == null)
				return false;
			dragBack = true;
			int maxLeft = Integer.MIN_VALUE, minLeft = Integer.MAX_VALUE;
			int maxIndex = 0, minIndex = 0;
			for (int i = 0; i < mAreaList.size(); i++) {
				a = mAreaList.get(i);
				if (a.bmap != null && a.layout.left > maxLeft) {
					maxLeft = a.layout.left;
					maxIndex = i;
				}
			}
			for (int i = 0; i < mAreaList.size(); i++) {
				a = mAreaList.get(i);
				if (a.bmap != null && a.layout.left < minLeft) {
					minLeft = a.layout.left;
					minIndex = i;
				}
			}

			if (maxIndex == minIndex) {
				if (maxLeft < mLayoutRectInfo[mMidPoint].left) {
					int span = mLayoutRectInfo[mMidPoint].left - maxLeft
							+ mLeftSpanWithMid;
					prevIncreamentDeltaX = -1;
					createMoveSpan(span);

					post(this);
					return true;
				} else {
					int span = maxLeft - mLayoutRectInfo[mMidPoint].left
							+ mLeftSpanWithMid;
					prevIncreamentDeltaX = 1;
					createMoveSpan(span);
					post(this);
					return true;
				}
			}

			if (maxLeft < mLayoutRectInfo[mMidPoint].left) {
				int span = mLayoutRectInfo[mMidPoint].left - maxLeft;
				prevIncreamentDeltaX = -1;
				createMoveSpan(span);

				post(this);
				return true;
			} else {
				if (minLeft > mLayoutRectInfo[mMidPoint].left) {
					int span = minLeft - mLayoutRectInfo[mMidPoint].left;
					prevIncreamentDeltaX = 1;
					createMoveSpan(span);

					post(this);
					return true;
				} else {
					LOGD("#####in startDragBack startAreaAnimation()####");
					LOGD("@#####maxLeft = " + maxLeft + ",  minLeft = "
							+ minLeft + "@@@@");
					LOGD("#####maxIndex = " + maxIndex + ", minIndex = "
							+ minIndex + "#####");

					if (maxLeft - mLayoutRectInfo[mMidPoint].left >= mLeftSpanWithMid) {
						// return startAreaAnimation();
						if (mLayoutRectInfo[mMidPoint].left - minLeft >= mLeftSpanWithMid) {
							return startAreaAnimation();
						} else {
							prevIncreamentDeltaX = 1;
							return startAreaAnimation();
						}
					} else {
						prevIncreamentDeltaX = -1;
						return startAreaAnimation();
					}
				}
			}
		}

		private int findMostNearestLeftFromArea(int left) {
			int nearestLeft = 0;
			for (int i = mMaxCount - 1; i >= 0; i--) {
				if (left > mLayoutRectInfo[i].left) {
					nearestLeft = mLayoutRectInfo[i].left;
					break;
				}
			}
			return nearestLeft;
		}

		private int findMostNearestRightFromArea(int left) {
			int nearestRight = 0;
			for (int i = 0; i < mMaxCount; i++) {
				if (left < mLayoutRectInfo[i].left) {
					nearestRight = mLayoutRectInfo[i].left;
					break;
				}
			}
			return nearestRight;
		}

		public void resetPro() {
			index = 0;
			moveCount = 10;
			lastNeedMerge = false;
			moveSpanMerge = 0;
			fromStart = false;
			dragBack = false;
			moveSpan = 0;
		}

		public boolean startAreaAnimation() {
			int size = mAreaList.size();
			Area firstAreaNotCompliance = null;
			Area nextArea = null;
			LOGD("@@@@prevIncreamentDeltaX = " + prevIncreamentDeltaX + "@@@@@");
			if (prevIncreamentDeltaX > 0) {
				for (int i = 0; i < size; i++) {
					Area a = mAreaList.get(i);
					if (a.bmap != null) {
						firstAreaNotCompliance = a;
						if (i < size - 1) {
							nextArea = mAreaList.get(i + 1);
						}
						break;
					}
				}
			} else if (prevIncreamentDeltaX < 0) {
				for (int i = size - 1; i >= 0; i--) {
					Area a = mAreaList.get(i);
					if (a.bmap != null) {
						firstAreaNotCompliance = a;
						if (i > 0) {
							nextArea = mAreaList.get(i - 1);
						}
						break;
					}
				}
			}
			if (firstAreaNotCompliance != null) {
				if (prevIncreamentDeltaX > 0) {
					if (firstAreaNotCompliance.layout.left > mLayoutRectInfo[mMidPoint].left) {
						int span = firstAreaNotCompliance.layout.left
								- mLayoutRectInfo[mMidPoint].left;
						LOGD("##startAreaAnimatino span = " + span + "####");
						LOGD("###startAreaAnimation moveCount = " + moveCount
								+ "####");

						dragBack = true;
						createMoveSpan(span);
						post(this);
						return true;
					} else if (firstAreaNotCompliance.layout.left <= mLayoutRectInfo[mMidPoint].left
							&& firstAreaNotCompliance.layout.left > 0) {
						int areaLeft = findMostNearestLeftFromArea(firstAreaNotCompliance.layout.left);
						int span = firstAreaNotCompliance.layout.left
								- areaLeft;
						LOGD("##startAreaAnimatino span = " + span + "####");
						LOGD("###startAreaAnimation moveCount = " + moveCount
								+ "####");
						dragBack = true;
						createMoveSpan(span);
						post(this);
						return true;
					} else {
						int span = nextArea.layout.left - 0;
						LOGD("##startAreaAnimatino span = " + span + "####");
						LOGD("###startAreaAnimation moveCount = " + moveCount
								+ "####");
						dragBack = true;
						createMoveSpan(span);
						fromStart = true;
						post(this);
						return true;
					}
				} else if (prevIncreamentDeltaX < 0) {
					if (firstAreaNotCompliance.layout.right < mLayoutRectInfo[mMidPoint].right) {
						int span = -firstAreaNotCompliance.layout.left
								+ mLayoutRectInfo[mMidPoint].left;
						LOGD("##startAreaAnimatino span = " + span + "####");
						LOGD("###startAreaAnimation moveCount = " + moveCount
								+ "####");
						dragBack = true;
						createMoveSpan(span);
						post(this);
						return true;
					} else if (firstAreaNotCompliance.layout.right >= mLayoutRectInfo[mMidPoint].right
							&& firstAreaNotCompliance.layout.right < mLayoutRectInfo[mMaxCount - 1].right) {
						int areaLeft = findMostNearestRightFromArea(firstAreaNotCompliance.layout.left);
						int span = -firstAreaNotCompliance.layout.left
								+ areaLeft;
						LOGD("##startAreaAnimatino span = " + span + "####");
						LOGD("###startAreaAnimation moveCount = " + moveCount
								+ "####");
						dragBack = true;
						createMoveSpan(span);
						post(this);
						return true;
					} else {
						int span = -nextArea.layout.left
								+ mLayoutRectInfo[mMaxCount - 1].left;
						LOGD("##startAreaAnimatino span = " + span + "####");
						LOGD("###startAreaAnimation moveCount = " + moveCount
								+ "####");
						dragBack = true;
						createMoveSpan(span);
						fromStart = true;
						post(this);
						return true;
					}
				}
			} else {

			}
			return false;
		}

		private void endFling() {
			mTouchMode = TOUCH_MODE_REST;

		}

		private void adjustAreaByLayoutInfo(Area a, int i) {
			a.layout.left = mLayoutRectInfo[i].left;
			a.layout.right = a.layout.left + mAreaWidth;
			if (i == mMidPoint) {
				a.canvasMatrix = new Matrix();
				a.currentRotateAngle = 0.0f;
				a.type = MID;
			} else if (i < mMidPoint) {
				a.canvasMatrix = getImageMatrix(0, mAreaHeight / 2,
						mRotateAngle);
				a.currentRotateAngle = mRotateAngle;
				a.type = LEFT;
			} else {
				a.canvasMatrix = getImageMatrix(mAreaWidth, mAreaHeight / 2,
						-mRotateAngle);
				a.currentRotateAngle = -mRotateAngle;
				a.type = RIGHT;
			}
		}

		private void adjustAreaLayout() {
			mMoveCount = 0;
			if (prevIncreamentDeltaX < 0) {
				if (fromStart) {
					fromStart = false;

					int offset = mAreaList.size() - 1;
					for (int i = mMaxCount - 1; i >= 0; i--) {
						Area a = null;
						if (offset < 0) {
							a = new Area();
							mAreaList.add(0, a);
							int firstPos = getFirstPosition();
							LOGD("####run() mFirstPosition = " + firstPos
									+ "##");
							LOGD("####run() offset = " + offset + "###");
							firstPos += offset;
							// changeFirstPosition(firstPos);
							a.bmap = getBitmapByPosition(firstPos);
							a.clipRect.left = 0;
							a.clipRect.right = mAreaWidth;
							a.clipRect.top = 0;
							a.clipRect.bottom = mAreaHeight;
							a.layout.top = 0;
							a.layout.bottom = mAreaHeight;
							mMoveCount--;
						} else {
							a = mAreaList.get(offset);
						}
						adjustAreaByLayoutInfo(a, i);
						offset--;
					}
					return;
				}
				int offset = 0;
				for (int i = 0; i < mMaxCount; i++) {
					if (offset >= mAreaList.size()) {
						break;
					}
					Area a = mAreaList.get(i);
					adjustAreaByLayoutInfo(a, i);
					offset++;
				}
			} else if (prevIncreamentDeltaX > 0) {
				if (fromStart) {
					fromStart = false;
					int offset = 0;
					for (int i = 0; i < mMaxCount; i++) {

						Area a = null;
						if (offset >= mAreaList.size()) {
							a = new Area();
							mAreaList.add(a);
							int firstPos = getFirstPosition();
							firstPos++;
							LOGD("####run() mFirstPosition = " + firstPos + "##");
							LOGD("####run() offset = " + offset + "###");
							a.bmap = getBitmapByPosition(firstPos + offset);
							a.clipRect.left = 0;
							a.clipRect.right = mAreaWidth;
							a.clipRect.top = 0;
							a.clipRect.bottom = mAreaHeight;
							a.layout.top = 0;
							a.layout.bottom = mAreaHeight;
							mMoveCount++;
						} else {
							a = mAreaList.get(offset);
						}
						adjustAreaByLayoutInfo(a, i);
						offset++;
					}
					return;
				}
				int offset = mAreaList.size() - 1;
				for (int i = mMaxCount - 1; i >= 0; i--) {
					if (offset < 0) {
						break;
					}
					Area a = mAreaList.get(offset);
					adjustAreaByLayoutInfo(a, i);
					offset--;
				}
			}
		}

		private void doUpdateWhenDragBack() {
			if (index < moveCount) {
				if (index == (moveCount - 1) && lastNeedMerge) {
					moveSpan = moveSpanMerge;
				}
				LOGD("####moveSpan = " + moveSpan);
				trackMotionScroll(moveSpan, moveSpan);
				index++;
				if (index == moveCount) {
					adjustAreaLayout();
					SetCurrentIdx(mMoveCount);
					invalidate();

					Message numsg = mHandler.obtainMessage(END_FLING, null);
					mHandler.removeMessages(END_FLING);
					mHandler.sendMessageDelayed(numsg, 100);

				}
				post(this);
			} else {
				mTouchMode = TOUCH_MODE_REST;
				dragBack = false;
				prevIncreamentDeltaX = 0;
			}
		}

		private final Handler mHandler = new Handler() {
			@Override
			public void handleMessage(Message msg) {
				switch (msg.what) {
				case END_FLING:
					mInterface.HandleEndFlingEvent(mCurrentDirection == 1);
					// isFling = false;
					break;
				}
			}
		};

		public void run() {
			if (mTouchMode != TOUCH_MODE_FLING) {
				return;
			}

			if (mItemCount == 0) {
				endFling();
				return;
			}
			if (dragBack) {
				LOGD("####fling index = " + index + "####");
				doUpdateWhenDragBack();
				return;
			}
			final Scroller scroller = mScroller;
			boolean more = scroller.computeScrollOffset();
			final int x = scroller.getCurrX();

			// Flip sign to convert finger direction to list items direction
			// (e.g. finger moving down means list is moving towards the top)
			int delta = mLastFlingX - x;

			// Pretend that each frame of a fling scroll is a touch scroll
			if (delta > 0) {
				// Don't fling more than 1 screen
				delta = Math.min(getWidth() - getPaddingRight()
						- getPaddingLeft() - 1, delta);
			} else {
				// Don't fling more than 1 screen
				delta = Math.max(-(getWidth() - getPaddingRight()
						- getPaddingLeft() - 1), delta);
			}

			trackMotionScroll(delta, delta);

			// if(prevIncreamentDeltaX == 0 && delta != prevIncreamentDeltaX)
			if (more && delta != 0) {
				LOGD("###run() delta = " + delta + "#####");
				prevIncreamentDeltaX = delta;
			}
			if (more && noneNullAreaSize() > 1) {
				mLastFlingX = x;

				post(this);
			} else {
				LOGD("####noneNullAreaSize() = " + noneNullAreaSize());
				LOGD("####prevIncreamentDeltaX = " + prevIncreamentDeltaX);
				int noneNullAreaCount = noneNullAreaSize();
				if (noneNullAreaCount < mMaxCount) {
					LOGD("####run() startDrawBack()####");
					resetPro();
					boolean ret = startDragBack();
					if (ret)
						return;
				} else {
					LOGD("####run() startAreaAnimation()####");
					resetPro();
					boolean ret = startAreaAnimation();
					LOGD("#####ret = " + ret + "####");
					if (ret)
						return;
				}
				endFling();
			}
		}
	}

	private Bitmap getBitmapByPosition(int pos) {
		int size = mTransBitmapList.size();
		return mTransBitmapList.get((pos + size) % size);
		// int size = mTransBitmapList.size();
		// if (pos >= size || pos < 0) {
		// return null;
		// } else {
		// if (mTransBitmapList.isEmpty()) {
		// return null;
		// }
		// return mTransBitmapList.get(pos);
		// }
	}

	private int noneNullAreaSize() {
		int count = 0;
		for (int i = 0; i < mAreaList.size(); i++) {
			Area a = mAreaList.get(i);
			if (a.bmap != null)
				count++;
		}
		return count;
	}

	private void calculateAreaRotatePro(Area a, int dir) {
		if (dir == 0) // to left
		{
			if (a.layout.left <= mLayoutRectInfo[mMidPoint - 1].left) {
				a.currentRotateAngle = mRotateAngle;
				a.canvasMatrix = getImageMatrix(0, mAreaHeight / 2,
						a.currentRotateAngle);
			} else if (a.layout.left > mLayoutRectInfo[mMidPoint - 1].left
					&& a.layout.left < mLayoutRectInfo[mMidPoint].left) {
				float rate = ((float) (mLayoutRectInfo[mMidPoint].left - a.layout.left))
						/ mLeftSpanWithMid;
				a.currentRotateAngle = rate * mRotateAngle;
				if (a.currentRotateAngle >= mRotateAngle) {
					a.currentRotateAngle = mRotateAngle;
				}
				a.canvasMatrix = getImageMatrix(0, mAreaHeight / 2,
						a.currentRotateAngle);
			} else if (a.layout.left == mLayoutRectInfo[mMidPoint].left) {
				a.currentRotateAngle = 0.0f;
				// a.canvasMatrix = new Matrix();
				a.canvasMatrix = getImageMatrix(0, mAreaHeight / 2,
						a.currentRotateAngle);
			} else if (a.layout.left > mLayoutRectInfo[mMidPoint].left
					&& a.layout.left < mLayoutRectInfo[mMidPoint + 1].left) {
				float rate = ((float) ((mLayoutRectInfo[mMidPoint + 1].left - a.layout.left)))
						/ mLeftSpanWithMid;
				a.currentRotateAngle = (1 - rate) * (-mRotateAngle);
				if (a.currentRotateAngle >= 0.0f) {
					a.currentRotateAngle = 0.0f;
				}

				a.canvasMatrix = getImageMatrix(mAreaWidth, mAreaHeight / 2,
						a.currentRotateAngle);

			} else if (a.layout.left >= mLayoutRectInfo[mMidPoint + 1].left) {
				a.currentRotateAngle = -mRotateAngle;
				a.canvasMatrix = getImageMatrix(mAreaWidth, mAreaHeight / 2,
						a.currentRotateAngle);
			}
		} else if (dir == 1) {
			if (a.layout.right >= mLayoutRectInfo[mMidPoint + 1].right) {
				a.currentRotateAngle = -mRotateAngle;
				a.canvasMatrix = getImageMatrix(mAreaWidth, mAreaHeight / 2,
						a.currentRotateAngle);
			} else if (a.layout.right < mLayoutRectInfo[mMidPoint + 1].right
					&& a.layout.right > mLayoutRectInfo[mMidPoint].right) {
				float rate = ((float) (a.layout.right - mLayoutRectInfo[mMidPoint].right))
						/ mLeftSpanWithMid;
				a.currentRotateAngle = rate * (-mRotateAngle);
				if (a.currentRotateAngle < -mRotateAngle) {
					a.currentRotateAngle = -mRotateAngle;
				}
				a.canvasMatrix = getImageMatrix(mAreaWidth, mAreaHeight / 2,
						a.currentRotateAngle);
			} else if (a.layout.right == mLayoutRectInfo[mMidPoint].right) {
				a.currentRotateAngle = 0.0f;
				// a.canvasMatrix = new Matrix();
				a.canvasMatrix = getImageMatrix(mAreaWidth, mAreaHeight / 2,
						a.currentRotateAngle);
			} else if (a.layout.right < mLayoutRectInfo[mMidPoint].right
					&& a.layout.right > mLayoutRectInfo[mMidPoint - 1].right) {
				float rate = ((float) ((a.layout.right - mLayoutRectInfo[mMidPoint - 1].right)))
						/ mLeftSpanWithMid;
				a.currentRotateAngle = (1.0f - rate) * mRotateAngle;
				if (a.currentRotateAngle < 0.0f) {
					a.currentRotateAngle = 0.0f;
				}
				a.canvasMatrix = getImageMatrix(0, mAreaHeight / 2,
						a.currentRotateAngle);

			} else if (a.layout.right <= mLayoutRectInfo[mMidPoint - 1].right) {
				a.currentRotateAngle = mRotateAngle;
				a.canvasMatrix = getImageMatrix(0, mAreaHeight / 2,
						a.currentRotateAngle);
			}
		}
	}

	private void setAreaType() {
		for (int i = 0; i < mAreaList.size(); i++) {
			Area a = mAreaList.get(i);
			if (a.currentRotateAngle <= mRotateAngle
					&& a.currentRotateAngle > 0.0f) {
				a.type = LEFT;
			} else if (a.currentRotateAngle >= -mRotateAngle
					&& a.currentRotateAngle < 0.0f) {
				a.type = RIGHT;
			} else {
				a.type = MID;
			}
		}
	}

	private void updateLayoutToLeft(int deltaX, int increamentDeltaX) {
		if (mAreaList.size() == 0) {
			return;
		}
		for (int i = 0; i < mAreaList.size(); i++) {
			Area a = mAreaList.get(i);
			a.layout.left += increamentDeltaX;
			a.layout.right += increamentDeltaX;
			a.clipRect.left += increamentDeltaX;
			a.clipRect.right += increamentDeltaX;
		}
		Area prevArea = mAreaList.get(0);
		for (int i = 1; i < mAreaList.size(); i++) {
			Area a = mAreaList.get(i);
			if (a.layout.left - prevArea.layout.left != mLeftSpanWithMid) {
				LOGD("###do stepx adjust####");
				a.layout.left = prevArea.layout.left + mLeftSpanWithMid;
				a.layout.right = a.layout.left + mAreaWidth;
				a.layout.top = 0;
				a.layout.bottom = mAreaHeight;
				a.clipRect.left = 0;
				a.clipRect.right = mAreaWidth;
				a.clipRect.top = 0;
				a.clipRect.bottom = mAreaHeight;
			}
			prevArea = a;
		}
		for (int i = 0; i < mAreaList.size(); i++) {
			Area a = mAreaList.get(i);
			calculateAreaRotatePro(a, 0);
		}
		setAreaType();
		ArrayList<Area> tmpList = new ArrayList<Area>();
		int removedCount = 0;
		for (int i = 0; i < mAreaList.size(); i++) {
			Area a = mAreaList.get(i);
			if ((a.type == LEFT && ((a.layout.left + mLeftSpanWithMid) <= 0))
					|| (a.layout.right <= 0)) {
				removedCount++;
			} else {
				tmpList.add(a);
			}
		}
		for (int i = 0; i < removedCount; i++) {
			// tmpList.add(mAreaList.get(i));
		}
		LOGD("removedCount = " + removedCount);
		mAreaList.clear();
		mAreaList = tmpList;
		// int firstPos = getFirstPosition();
		// firstPos += removedCount;
		// changeFirstPosition(firstPos);
		// if (firstPos >= mItemCount) {
		// firstPos = mItemCount - 1;
		// changeFirstPosition(firstPos);
		// }
		int size = mAreaList.size();
		// LOGD("left mFirstPostion = " + firstPos);
		LOGD("left size = " + size);
		if (size == 0) {
			initLayout();
			// startAreaAnimation();mAreaList
			Log.e("CoverFlowView",
					"$$$$$$ERROR : left scroll can't exceed one screen$$$$$$");
			return;
		}
		Area rightMostArea = null;
		int removeCount = 0;
		for (int i = mAreaList.size() - 1; i >= 0; i--) {
			Area a = mAreaList.get(i);
			if (a.bmap != null) {
				rightMostArea = a;
				break;
			} else {
				removeCount++;
			}
		}
		int dstToRightEdge;
		if (rightMostArea != null) {
			if (rightMostArea.type == RIGHT || rightMostArea.type == MID) {
				dstToRightEdge = getWidth() - rightMostArea.layout.right;
			} else {
				dstToRightEdge = getWidth()
						- (rightMostArea.layout.left + mLeftSpanWithMid);
			}
			for (int i = 0; i < removeCount; i++) {
				mAreaList.remove(mAreaList.size() - 1);
			}
		} else {
			mAreaList.clear();
			initLayout();
			return;
		}
		if (dstToRightEdge > 0) {

			int left = rightMostArea.layout.left + mLeftSpanWithMid;
			int i = 0;
			size = mAreaList.size();
			while ((left + mAreaWidth) < (getWidth() + mLeftSpanWithMid)) {
				Area a = new Area();
				a.layout.left = left;
				a.layout.right = a.layout.left + mAreaWidth;
				a.layout.top = 0;
				a.layout.bottom = mAreaHeight;
				a.clipRect.left = 0;
				a.clipRect.right = mAreaWidth;
				a.clipRect.top = 0;
				a.clipRect.bottom = mAreaHeight;
				int firstPos = getFirstPosition();
				a.bmap = getBitmapByPosition(firstPos + size + i);
				calculateAreaRotatePro(a, 0);
				mAreaList.add(a);
				i++;
				left += mLeftSpanWithMid;
			}
			setAreaType();
			int addNum = i;
			LOGD("addNum = " + addNum);
			LOGD("left after add area size = " + mAreaList.size());
			adjustLeftAreaList();
		}

	}

	private void adjustLeftAreaList() {
		boolean needAdjust = true;
		int size = mAreaList.size();
		int noneNullCount = 0;
		for (int i = 0; i < size; i++) {
			Area a = mAreaList.get(i);
			if (a.bmap != null) {
				noneNullCount++;
			}
		}
		if (noneNullCount > 1) {
			needAdjust = false;
		}
		if (!needAdjust) {
			return;
		}
		mAreaList.clear();
		initLayout();
	}

	private void adjustRightAreaList() {
		boolean needAdjust = true;
		int size = mAreaList.size();
		int noneNullCount = 0;
		for (int i = size - 1; i >= 0; i--) {
			Area a = mAreaList.get(i);
			if (a.bmap != null) {
				noneNullCount++;
			}
		}
		if (noneNullCount > 1) {
			needAdjust = false;
		}
		if (!needAdjust) {
			return;
		}
		mAreaList.clear();
		initLayout();
	}

	private void updateLayoutToRight(int deltaX, int increamentDeltaX) {
		if (mAreaList.size() == 0) {
			return;
		}
		int oldSize = mAreaList.size();
		for (int i = 0; i < mAreaList.size(); i++) {
			Area a = mAreaList.get(i);
			a.layout.left += increamentDeltaX;
			a.layout.right += increamentDeltaX;
			a.clipRect.left += increamentDeltaX;
			a.clipRect.right += increamentDeltaX;
		}
		Area prevArea = mAreaList.get(mAreaList.size() - 1);
		for (int i = mAreaList.size() - 2; i >= 0; i--) {
			Area a = mAreaList.get(i);
			if (prevArea.layout.right - a.layout.right != mLeftSpanWithMid) {
				a.layout.right = prevArea.layout.right - mLeftSpanWithMid;
				a.layout.left = a.layout.right - mAreaWidth;
			}
			prevArea = a;
		}
		for (int i = 0; i < mAreaList.size(); i++) {
			Area a = mAreaList.get(i);
			calculateAreaRotatePro(a, 1);
		}
		setAreaType();
		ArrayList<Area> tmpList = new ArrayList<Area>();
		int removedCount = 0;
		for (int i = 0; i < mAreaList.size(); i++) {
			Area a = mAreaList.get(i);
			if ((a.type == RIGHT && ((a.layout.right - mLeftSpanWithMid) >= getWidth()))
					|| (a.layout.left >= getWidth())) {
				removedCount++;
			} else {
				tmpList.add(a);
				int size = tmpList.size();
			}
		}
		for (int i = 0; i < removedCount; i++) {
			// tmpList.add(0,mAreaList.get(mAreaList.size()-1-i));

		}
		LOGD("right removedCount = " + removedCount);
		mAreaList.clear();
		mAreaList = tmpList;
		int size = mAreaList.size();
		LOGD("right before size = " + size);
		int dstToLeftEdge;
		Area leftMostArea = null;
		int nullAreaCount = 0;
		for (int i = 0; i < size; i++) {
			Area a = mAreaList.get(i);
			if (a.bmap != null) {
				leftMostArea = a;
				LOGD("right leftMostAre.left = " + leftMostArea.layout.left);
				break;
			} else {
				nullAreaCount++;
			}
		}
		if (leftMostArea != null) {
			if (leftMostArea.type == LEFT || leftMostArea.type == MID) {
				dstToLeftEdge = leftMostArea.layout.left;
			} else {
				dstToLeftEdge = leftMostArea.layout.right - mLeftSpanWithMid;
			}
			for (int i = 0; i < nullAreaCount; i++) {
				mAreaList.remove(0);
				int firstPos = getFirstPosition();
				firstPos++;
				changeFirstPosition(firstPos);
				// mFirstPosition++;
			}
			LOGD("right dstToLeftEdge = " + dstToLeftEdge);
		} else {
			mAreaList.clear();
			int firstPos = getFirstPosition();
			// mFirstPosition -= oldSize;
			firstPos -= oldSize;
			if (firstPos <= -mMaxCount) {
				firstPos = -mMaxCount + 1;
				changeFirstPosition(firstPos);
			}
			LOGD("right mFirstPostion = " + firstPos);
			LOGD("@@@@@@@@ERROR: right scroll exceed one screen@@@@@@");
			initLayout();
			return;
		}
		if (dstToLeftEdge > 0) {
			int left = leftMostArea.layout.left - mLeftSpanWithMid;
			int i = 1;
			while (left > -mLeftSpanWithMid) {
				Area a = new Area();
				a.layout.left = left;// leftMostArea.layout.right - (i + 1) *
				// (mAreaStepX + 10);
				// Log.i("CoverFlowView", "a.layout.left = " + a.layout.left);
				a.layout.right = a.layout.left + mAreaWidth;
				a.layout.top = 0;
				a.layout.bottom = mAreaHeight;
				a.clipRect.left = 0;
				a.clipRect.right = mAreaWidth;
				a.clipRect.top = 0;
				a.clipRect.bottom = mAreaHeight;
				int firstPos = getFirstPosition();
				a.bmap = getBitmapByPosition(firstPos - i);
				calculateAreaRotatePro(a, 1);
				mAreaList.add(0, a);
				i++;
				left -= mLeftSpanWithMid;
			}
			setAreaType();
			int addNum = i - 1;
			LOGD("right addnum = " + addNum);
			int firstPos = getFirstPosition();
			firstPos -= addNum;
			changeFirstPosition(firstPos);
			if (firstPos <= -mMaxCount) {
				firstPos = -mMaxCount + 1;
				changeFirstPosition(firstPos);
			}

			LOGD("right after add area size = " + mAreaList.size());
			LOGD("right after add area mFirstPosition = " + firstPos);
			adjustRightAreaList();
		}

	}

	private void updateLayout(int deltaX, int increamentDeltaX) {
		int limitScrollSpan = getWidth() - mAreaWidth;
		if (increamentDeltaX < 0) {
			if (increamentDeltaX < -limitScrollSpan) {
				increamentDeltaX = -limitScrollSpan;
			}
			mCurrentDirection = 0;
			updateLayoutToLeft(deltaX, increamentDeltaX);
		} else if (increamentDeltaX > 0) {
			if (increamentDeltaX > limitScrollSpan) {
				increamentDeltaX = limitScrollSpan;
			}
			mCurrentDirection = 1;
			updateLayoutToRight(deltaX, increamentDeltaX);
		}
	}

	private void trackMotionScroll(int deltaX, int increamentDeltaX) {
		LOGD("####deltaX = " + deltaX + ", increamentDeltaX = "
				+ increamentDeltaX + "####");
		if (increamentDeltaX == 0) {
			return;
		}
		updateLayout(deltaX, increamentDeltaX);
		invalidate();
	}

	private void initLayoutRectInfo(int width, int height) {
		int startx = 0;
		int starty = 0;
		for (int i = 0; i < mMidPoint; i++) {
			mLayoutRectInfo[i].left = startx + i * mAreaStepX;
			mLayoutRectInfo[i].top = starty + i * mAreaStepY;
			mLayoutRectInfo[i].bottom = mAreaHeight + mLayoutRectInfo[i].top;
			mLayoutRectInfo[i].right = mAreaWidth + mLayoutRectInfo[i].left;
		}
		startx = width - mAreaWidth;
		starty = 0;
		int offset = mMaxCount - 1;
		for (int i = mMaxCount - 1; i >= mMidPoint + 1; i--) {
			mLayoutRectInfo[i].left = startx + (offset - i) * (-mAreaStepX);
			mLayoutRectInfo[i].top = starty + (offset - i) * mAreaStepY;
			mLayoutRectInfo[i].bottom = mAreaHeight + mLayoutRectInfo[i].top;
			mLayoutRectInfo[i].right = mAreaWidth + mLayoutRectInfo[i].left;
		}
		mLayoutRectInfo[mMidPoint].left = (width - mAreaWidth) / 2;
		mLayoutRectInfo[mMidPoint].top = starty;
		mLayoutRectInfo[mMidPoint].right = mLayoutRectInfo[mMidPoint].left
				+ mAreaWidth;
		mLayoutRectInfo[mMidPoint].bottom = mLayoutRectInfo[mMidPoint].top
				+ mAreaHeight;
	}

	private void parseAreaValue(String name, String value) {

		if (name.equalsIgnoreCase("rotateangle")) {
			// mAreaAttribute[area].rotateAngle = Float.parseFloat(value);
			mRotateAngle = Float.parseFloat(value);
		} else if (name.equalsIgnoreCase("areawidth")) {
			// mAreaAttribute[area].width = Integer.parseInt(value);
			mAreaWidth = Integer.parseInt(value);
		} else if (name.equalsIgnoreCase("areaheight")) {
			// mAreaAttribute[area].height = Integer.parseInt(value);
			mAreaHeight = Integer.parseInt(value);
		} else if (name.equalsIgnoreCase("stepx")) {
			// mAreaAttribute[area].stepX = Integer.parseInt(value);
			mAreaStepX = Integer.parseInt(value);
		} else if (name.equalsIgnoreCase("stepy")) {
			// mAreaAttribute[area].stepY = Integer.parseInt(value);
			mAreaStepY = Integer.parseInt(value);
		}
	}

	private void initAttribute(Context context, int attributeId) {
		XmlPullParser parser = context.getResources().getAnimation(attributeId);
		try {
			int eventType = parser.getEventType();
			while (eventType != XmlPullParser.END_DOCUMENT) {
				if (eventType == XmlPullParser.START_TAG) {
					String elementName = parser.getName();
					int attributeSize = parser.getAttributeCount();
					for (int i = 0; i < attributeSize; i++) {
						String name = parser.getAttributeName(i);
						String value = parser.getAttributeValue(i);
						if (elementName.equals("CoverFlowViewAttribute")) {
							if (name.equalsIgnoreCase("maxcount")) {
								mMaxCount = Integer.parseInt(value);
							} else if (name.equalsIgnoreCase("reflection")) {
								mReflection = Float.parseFloat(value);
							} else if (name.equalsIgnoreCase("depth")) {
								mDepth = Float.parseFloat(value);
							}
						} else if (elementName.equals("AreaAttribute")) {
							parseAreaValue(name, value);
						}

					}
				}
				eventType = parser.next();
			}
		} catch (XmlPullParserException e) {
			return;
		} catch (java.io.IOException e) {
			return;
		}
		return;
	}

	// protected void setSelectionInt(int position) {
	//
	// }

	private void drawLeftAreas(Canvas canvas) {
		ListIterator<Area> it = mAreaList.listIterator();
		while (it.hasNext()) {
			Area a = (Area) it.next();
			if (a.type == LEFT || a.type == LEFT_RIGHT_MOST) {
				canvas.save();
				canvas.translate(a.layout.left, a.layout.top);
				canvas.clipRect(new Rect(0, 0
				                         , a.clipRect.right - a.clipRect.left
				                         , a.clipRect.bottom - a.clipRect.top));
				canvas.concat(a.canvasMatrix);
				if (a.bmap != null) {
					Paint paint = new Paint();
					paint.setAntiAlias(true);
					canvas.drawBitmap(a.bmap, new Rect(0, 0, a.bmap.getWidth(),
							a.bmap.getHeight()), new Rect(0, 0, a.layout.right
							- a.layout.left, a.layout.bottom - a.layout.top),
							paint);
				}
				canvas.restore();
			}
		}
	}

	private void drawRightAreas(Canvas canvas) {
		ListIterator<Area> it = mAreaList.listIterator(mAreaList.size());
		while (it.hasPrevious()) {
			Area a = (Area) it.previous();
			if (a.type == RIGHT || a.type == RIGHT_LEFT_MOST) {
				canvas.save();
				canvas.translate(a.layout.left, a.layout.top);
				canvas.clipRect(new Rect(mAreaWidth
						- (a.clipRect.right - a.clipRect.left), 0, mAreaWidth,
						a.clipRect.bottom - a.clipRect.top));
				canvas.concat(a.canvasMatrix);
				if (a.bmap != null) {
					Paint paint = new Paint();
					paint.setAntiAlias(true);
					canvas.drawBitmap(a.bmap, new Rect(0, 0, a.bmap.getWidth(),
							a.bmap.getHeight()), new Rect(0, 0, a.layout.right
							- a.layout.left, a.layout.bottom - a.layout.top),
							paint);
				}
				canvas.restore();
			}
		}
	}

	private void drawMidArea(Canvas canvas) {
		ListIterator<Area> it = mAreaList.listIterator();
		while (it.hasNext()) {
			Area a = (Area) it.next();
			if (a.type == MID) {
				canvas.save();
				canvas.translate(a.layout.left, a.layout.top);
				canvas.clipRect(new Rect(0, 0, a.clipRect.right
						- a.clipRect.left, a.clipRect.bottom - a.clipRect.top));
				canvas.concat(a.canvasMatrix);
				if (a.bmap != null) {
					canvas.drawBitmap(a.bmap, new Rect(0, 0, a.bmap.getWidth(),
							a.bmap.getHeight()), new Rect(0, 0, a.layout.right
							- a.layout.left, a.layout.bottom - a.layout.top),
							null);
				}
				canvas.restore();
			}
		}
	}

	@Override
	protected void onDraw(Canvas canvas) {

		// List<Area> mReverseAreaList = Collections.reverseOrder(mRightArea);
		if (mCurrentDirection == 0) {
			drawLeftAreas(canvas);
			drawRightAreas(canvas);
			drawMidArea(canvas);
		} else if (mCurrentDirection == 1) {
			drawRightAreas(canvas);
			drawLeftAreas(canvas);
			drawMidArea(canvas);
		}

	}

	private void updateByOrientation() {
	}

	private void scaleImageList(Adapter adapter) {
		int size = adapter.getCount();
		
		int curIdx = ((BitmapAdapter) adapter).GetInitIndex();
		if (curIdx == -1)
			curIdx = 0;
		for (int i = 0; i < size; i++) {
			// Object obj = adapter.getItem((curIdx - mMaxCount / 2 + i + size)
			// % size);
			Object obj = adapter.getItem(i);
			Bitmap bmap = null;
			if (obj instanceof Bitmap) {
				bmap = (Bitmap) obj;
				Bitmap transBmap = getBitmap(bmap, mAreaWidth, mAreaHeight, FILL);
				mTransBitmapList.add(transBmap);
			}
		}
	}

	private Matrix getImageMatrix(float centerX, float centerY, float angle) {
		mCamera.save();
		mCamera.translate(0.0f, 0.0f, mDepth);
		mCamera.rotateY(angle);
		Matrix matrix = new Matrix();
		mCamera.getMatrix(matrix);
		mCamera.restore();
		matrix.preTranslate(-centerX, -centerY);
		matrix.postTranslate(centerX, centerY);
		// debug
		float values[] = new float[9];
		matrix.getValues(values);
		// Log.i("HelloWorld", "Matrix values:");
		// Log.i("HelloWorld", values[0] + " " + values[1] + " " + values[2]);
		// Log.i("HelloWorld", values[3] + " " + values[4] + " " + values[5]);
		// Log.i("HelloWorld", values[6] + " " + values[7] + " " + values[8]);
		// end
		return matrix;

	}

	protected final class CheckForLongPress implements Runnable {
		public void run() {
			final boolean handled = performLongPress();
			if (handled) {
				mTouchMode = TOUCH_MODE_REST;
			} else {
				mTouchMode = TOUCH_MODE_DONE_WAITING;
			}

		}
	}

	private boolean performLongPress() {
		return false;
	}

	protected final class CheckForTap implements Runnable {
		public void run() {
			if (mTouchMode == TOUCH_MODE_DOWN) {
				mTouchMode = TOUCH_MODE_TAP;

				final int longPressTimeout = ViewConfiguration
						.getLongPressTimeout();
				final boolean longClickable = isLongClickable();

				if (longClickable) {
					if (mPendingCheckForLongPress == null) {
						mPendingCheckForLongPress = new CheckForLongPress();
					}
					postDelayed(mPendingCheckForLongPress, longPressTimeout);
				} else {
					mTouchMode = TOUCH_MODE_DONE_WAITING;
				}
			}
		}
	}

	private int getAreaIndexByPos(int x, int y) {
		int index = -1;

		if (mLayoutRectInfo[mMidPoint].contains(x, y)) {
			return mMidPoint;
		}
		for (int i = mMidPoint - 1; i >= 0; i--) {
			if (mLayoutRectInfo[i].contains(x, y)) {
				return i;
			}
		}
		for (int i = mMidPoint + 1; i < mMaxCount; i++) {
			if (mLayoutRectInfo[i].contains(x, y)) {
				return i;
			}
		}
		return index;
	}

	// there may be some problem with the boolean return value
	// 'cause it's used in the on touch event event
	// and return value is necessary
	public boolean FlingCover(boolean isLeft) {
		isFling = true;

		int idx = mMaxCount / 2;
		idx += isLeft ? -1 : 1;
		int areaIndex = idx;
		Area a = mAreaList.get(areaIndex);
		if (mFlingRunnable == null) {
			mFlingRunnable = new FlingRunnable();
		}
		if (a.type == RIGHT && a.bmap != null) {
			mFlingRunnable.prevIncreamentDeltaX = 1;
			mFlingRunnable.resetPro();
			mFlingRunnable.dragBack = true;
			mFlingRunnable.fromStart = true;
			int span = (areaIndex - mMidPoint) * mLeftSpanWithMid;
			// + mLeftSpanWithMid;// a.layout.left -
			// mLayoutRectInfo[mMidPoint].left;
			if (span > mFlingRunnable.moveCount) {
				mFlingRunnable.moveSpan = -span / mFlingRunnable.moveCount;
				if (span % mFlingRunnable.moveCount > 0) {
					mFlingRunnable.lastNeedMerge = true;
					mFlingRunnable.moveSpanMerge = mFlingRunnable.moveSpan
							- span % mFlingRunnable.moveCount;
				}
			} else {
				mFlingRunnable.moveSpan = -1;
				mFlingRunnable.moveCount = span;
			}
			mFlingRunnable.startFling();
			return true;
		} else if (a.type == LEFT && a.bmap != null) {
			mFlingRunnable.prevIncreamentDeltaX = -1;
			mFlingRunnable.resetPro();
			mFlingRunnable.dragBack = true;
			mFlingRunnable.fromStart = true;
			int span = (mMidPoint - areaIndex) * mLeftSpanWithMid;// a.layout.left
			// -
			// mLayoutRectInfo[mMidPoint].left;
			if (span > mFlingRunnable.moveCount) {
				mFlingRunnable.moveSpan = span / mFlingRunnable.moveCount;
				if (span % mFlingRunnable.moveCount > 0) {
					mFlingRunnable.lastNeedMerge = true;
					mFlingRunnable.moveSpanMerge = mFlingRunnable.moveSpan
							+ span % mFlingRunnable.moveCount;
				}
			} else {
				mFlingRunnable.moveSpan = 1;
				mFlingRunnable.moveCount = span;
			}
			mFlingRunnable.startFling();
			return true;
		} else if (a.type == MID && a.bmap != null) {
			mMidAreaClickListener.onClick();
		}
		return false;
	}

	private int downPosX = -1;
	private final static int moveLimit = 20;

	// private boolean mClickArea = false;
	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		if (isFling)
			return true;
		final int action = ev.getAction();
		final int x = (int) ev.getX();
		final int y = (int) ev.getY();
		if (mVelocityTracker == null) {
			mVelocityTracker = VelocityTracker.obtain();
		}
		mVelocityTracker.addMovement(ev);

		switch (action) {
		case MotionEvent.ACTION_DOWN: {
			downPosX = x;
			break;
		}
		case MotionEvent.ACTION_UP: {
			if (x - downPosX > moveLimit) {
				if (FlingCover(true))
					return true;
			} else if (x - downPosX < -moveLimit) {
				if (FlingCover(false))
					return true;
			} else {
				int areaIndex = getAreaIndexByPos(x, y);
				if (areaIndex != -1) {
					if (areaIndex == mMaxCount / 2)
						mInterface.HandleTouchMidCoverEvent();
					else {
						boolean isLeft = areaIndex < mMaxCount / 2;
						if (FlingCover(isLeft))
							return true;
					}
					return true;
				}
			}
		}
		default:
		}
		return true;
	}

	@Override
	protected void onLayout(boolean changed, int left, int top, int right,
			int bottom) {
		if (mTransBitmapList.size() > 0) {
			LOGD("4 =" + Integer.toString(mTransBitmapList.size()));
			updateByOrientation();
			initLayoutRectInfo(right - left, bottom - top);
			initLayout();
			mLeftSpanWithMid = mLayoutRectInfo[mMidPoint].left
					- mLayoutRectInfo[mMidPoint - 1].left;
		}
	}

	private void initLayout() {
		for (int i = 0; i < mMaxCount; i++) {
			Area area = new Area();
			area.layout.left = mLayoutRectInfo[i].left;
			area.layout.top = mLayoutRectInfo[i].top;
			area.layout.right = mLayoutRectInfo[i].right;
			area.layout.bottom = mLayoutRectInfo[i].bottom;
			int firstPos = getFirstPosition();
			int size = mTransBitmapList.size();
			LOGD("list length1 =" + Integer.toString(size));
			area.bmap = getBitmapByPosition((firstPos + i + size) % size);
			if (i < mMidPoint) {
				area.canvasMatrix = getImageMatrix(0,
						mLayoutRectInfo[i].bottom / 2, mRotateAngle);
				area.clipRect.left = area.layout.left;
				area.clipRect.right = area.clipRect.left + mAreaWidth;
				area.clipRect.top = area.layout.top;
				area.clipRect.bottom = area.layout.top + mAreaHeight;
				area.currentRotateAngle = mRotateAngle;
				area.type = LEFT;
				if (i == mMidPoint - 1) {
					area.type = LEFT;// LEFT_RIGHT_MOST;
				}
			} else if (i == mMidPoint) {
				area.canvasMatrix = new Matrix();
				area.clipRect.left = area.layout.left;
				area.clipRect.right = area.layout.right;
				area.clipRect.top = area.layout.top;
				area.clipRect.bottom = area.layout.bottom;
				area.currentRotateAngle = 0.0f;
				area.type = MID;
			} else {
				area.canvasMatrix = getImageMatrix(
						mLayoutRectInfo[i].right - mLayoutRectInfo[i].left,
						(mLayoutRectInfo[i].bottom - mLayoutRectInfo[i].top) / 2,
						-mRotateAngle);
				area.clipRect.top = area.layout.top;
				area.clipRect.bottom = area.layout.bottom;
				area.clipRect.left = area.layout.left;
				area.clipRect.right = area.layout.right;
				area.currentRotateAngle = -mRotateAngle;
				area.type = RIGHT;
				if (i == mMidPoint + 1) {
					area.type = RIGHT;// RIGHT_LEFT_MOST;
				}
			}
			mAreaList.add(area);
		}
	}

	private Bitmap getBitmap(Bitmap srcBmap, int dstWidth, int dstHeight, int op) {
		if (op == SCALE) {
			return getBitmapByScale(srcBmap, dstWidth, dstHeight);
		} else if (op == FILL) {
			return getBitmapByFill(srcBmap, dstWidth, dstHeight);
		} else {
			return null;
		}

	}

	private Bitmap getBitmapByFill(Bitmap srcBmap, int dstWidth, int dstHeight) {
		int iconWidth = srcBmap.getWidth();
		int iconHeight = srcBmap.getHeight();
		if (iconWidth == dstWidth && iconHeight == dstHeight) {
			return srcBmap;
		}

		Bitmap thumb = Bitmap.createBitmap(dstWidth, dstHeight, srcBmap
				.getConfig());
		Canvas canvas = new Canvas(thumb);
		canvas.drawColor(0x00ffffff);
		// Bitmap mBit = srcBmap; // Bitmap.createBitmap(art, 2, 2,
		// art.width()-4, art.height()-4);
		Paint coverPaint = new Paint();
		// coverPaint.setAntiAlias(true);
		coverPaint.setFilterBitmap(true);
		coverPaint.setDither(true);

		BitmapShader sh1 = new BitmapShader(srcBmap, Shader.TileMode.REPEAT,
				Shader.TileMode.REPEAT);
		LinearGradient sh2 = new LinearGradient(0f, srcBmap.getHeight(), 0f,
				srcBmap.getHeight() * (1.0f - mReflection), 0x99ffffff,
				0x00ffffff, Shader.TileMode.CLAMP);
		// PorterDuff mode = new PorterDuff(PorterDuff.Mode.DST_IN);
		ComposeShader mReflectionShader = new ComposeShader(sh1, sh2,
				PorterDuff.Mode.DST_IN);
		int mywidth = dstWidth;
		int myheight = (int) (dstHeight * (1.0 - mReflection));
		float artwidth = srcBmap.getWidth();
		float artheight = srcBmap.getHeight();
		float xscale = ((float) (mywidth)) / artwidth;
		float yscale = ((float) (myheight)) / artheight;
		canvas.scale(xscale, yscale);
		coverPaint.setAlpha(255);
		canvas.drawBitmap(srcBmap, 0f, 0f, coverPaint);
//		Paint rectColor = new Paint();
//		rectColor.setColor(0xFFFF0000);
//		canvas.drawLine(0, 0, srcBmap.getWidth(), 0, rectColor);
//		canvas.drawLine(0, 0, 0, srcBmap.getHeight(), rectColor);
//		canvas.drawLine(0, srcBmap.getHeight(), srcBmap.getWidth(), srcBmap.getHeight(), rectColor);
//		canvas.drawLine(srcBmap.getWidth(), 0, srcBmap.getWidth(), srcBmap.getHeight(), rectColor);
		canvas.scale(1, -1, 0, srcBmap.getHeight());
		coverPaint.setAlpha(64);
		coverPaint.setShader(mReflectionShader);
		canvas.drawRect(new Rect(0, 0, srcBmap.getWidth(), srcBmap.getHeight()), coverPaint);
		coverPaint.setShader(null);
		return thumb;
	}

	private Bitmap getBitmapByScale(Bitmap srcbmap, int dstWidth, int dstHeight) {
		int width = dstWidth;
		int height = dstHeight;
		BitmapDrawable icon = new BitmapDrawable(srcbmap);
		int iconWidth = icon.getIntrinsicWidth();
		int iconHeight = icon.getIntrinsicHeight();
		if (width > 0 && height > 0
				&& (width < iconWidth || height < iconHeight)) {
			final float ratio = (float) iconWidth / iconHeight;
			if (iconWidth > iconHeight) {
				height = (int) (width / ratio);
			} else if (iconHeight > iconWidth) {
				width = (int) (height * ratio);
			}
			final Bitmap.Config c = icon.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
					: Bitmap.Config.RGB_565;
			final Bitmap thumb = Bitmap.createBitmap(width, height, c);
			final Canvas canvas = new Canvas(thumb);
			canvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG, 0));
			icon.setBounds(0, 0, width, height);
			// icon.setGravity(Gravity.CENTER_VERTICAL |
			// Gravity.CENTER_HORIZONTAL);
			icon.draw(canvas);
			return thumb;
		}
		return srcbmap;
	}

	private void LOGD(String text) {
		if (DEBUG) {
			Log.d(TAG, text);
		}
	}

	@Override
	public void setSelection(int position) {
		// TODO Auto-generated method stub

	}
}
